﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;

namespace Elvex
{
    public class Downloader : MonoBehaviour
    {
        enum TaskStatus
        {
            None, // 未开始
            Ing, // 进行中
            Completed, // 已完成
            Error, // 错误
        }

        class Task
        {
            public string URL { get; }

            public string Path { get; }

            public TaskStatus Status { get; set; } = TaskStatus.None;

            public Task(string url, string path)
            {
                URL = url;
                Path = path;
            }
        }

        /// <summary>
        /// Sets UnityWebRequest to attempt to abort after the number of seconds in timeout
        /// have passed.
        /// </summary>
        public int DownLoadTimeOut { get; set; } = 5;

        int m_maxDownloadNum = 3;

        public Downloader(int maxdownloadnum)
        {
            m_maxDownloadNum = maxdownloadnum;
        }

        public Downloader()
        {
            m_maxDownloadNum = 3;
        }

        List<Task> m_tasks = new List<Task>(); // 任务列表

        List<string> m_workTasks = new List<string>(); // 工作任务列

        public bool AddTask(string url, string path)
        {
            // 检查任务状态
            if (null != m_tasks.Find((i) => { return i.URL == url; }))
            {
                // 任务已存在
                return false;
            }

            var task = new Task(url, path);
            m_tasks.Add(task);

            if (m_workTasks.Count < m_maxDownloadNum)
            {
                StartCoroutine(Work(task));
            }
            return true;
        }

        public UnityEvent<string> OnDownloadCompleted { get; } = new UnityEvent<string>();

        public UnityEvent<string> OnDownloadError { get; } = new UnityEvent<string>();

        private IEnumerator Work(Task task)
        {
            m_workTasks.Add(task.URL);
            UnityWebRequest req = UnityWebRequest.Get(task.URL);
            req.timeout = DownLoadTimeOut;

            task.Status = TaskStatus.Ing;
            yield return req.SendWebRequest();
            if (req.result == UnityWebRequest.Result.ConnectionError)
            {
                task.Status = TaskStatus.Error;
                OnDownloadError.Invoke(task.URL);
                yield break;
            }
            else if(req.result == UnityWebRequest.Result.ProtocolError)
            {
                task.Status = TaskStatus.Error;
                OnDownloadError.Invoke(task.URL);
                yield break;
            }
            else
            {
                // 下载完成
                task.Status = TaskStatus.Completed;
                var taskdir = Path.GetDirectoryName(task.Path);
                if (!Directory.Exists(taskdir)) Directory.CreateDirectory(taskdir);
                var fs = new FileStream(task.Path, FileMode.Create);
                byte[] data = req.downloadHandler.data;
                fs.Write(data, 0, data.Length);
                fs.Close();
                req.Dispose();
                OnDownloadCompleted.Invoke(task.URL);
            }

            // 下一个任务
            var nexttask = m_tasks.Find((i) => { return i.Status == TaskStatus.None; });
            if (null != nexttask)
            {
                StartCoroutine(nameof(Work), nexttask);
            }
        }
    }
}
